#pragma once 

#include<iostream>
#include<string>
#include<assert.h>
#include<unistd.h>
#include"Log.hpp"
#include "Socket.hpp"
#include "Epoll.hpp"

namespace wyl
{
    #define PORT 8081
    const int gnum = 64;
    class EpollServer
    {
        using func_t = std::function<void(std::string)>;
    public:
        EpollServer(func_t handler_request, int port = PORT,int events_num = gnum): 
        _port(port),_events_num(events_num),_handler_request(handler_request)
        {
            _events = new struct epoll_event[_events_num];    
            _listen_sock = Socket::GetSocket();
            if(_listen_sock < 0)
            {
                DLOG("get listen sock failed\n");
                exit(1);
            }
            Socket::Bind(_listen_sock,_port); 
            Socket::Listen(_listen_sock);

            //1.创建epoll
            _epfd = Epoll::CreateEpoll(); 
            DLOG("create epoll success\n");
            //加入到epoll中 
            if(!Epoll::EpollCtl(_epfd,EPOLL_CTL_ADD,_listen_sock,EPOLLIN))
            {
                DLOG("listen sock add epoll failed\n");
                exit(4);
            }
            DLOG("get listen sock success\n");


        }
    
        void Start()
        {
            int timeout = 1000;
            while(true)
            {
                LoopOnce(timeout);
            }
        }
    
    private: 
        void LoopOnce(int timeout)
        {
            int n = Epoll::EpollWait(_epfd,_events,_events_num,timeout);
            switch(n)
            {
                case 0: DLOG("timeout ......\n"); break;
                case -1: ELOG("epoll_wait error , %d : %s\n" , errno, strerror(errno)); break;
                default: 
                    DLOG("get a event %d\n" , n);
                    HandlerEvent(n);
                    break;
            }
        }

        void HandlerEvent(int n)
        {
            assert(n > 0);
            for(int i = 0 ; i < n ; i++)
            {
                int sock = _events[i].data.fd;
                uint32_t ent = _events[i].events;
                if(ent & EPOLLIN)
                {
                    if(sock == _listen_sock) Accepter();
                    else Recver(i);
                }
            }
        }

        void Accepter()
        {   
            //接收套接字
            std::string client_ip;
            uint16_t client_port;
            int sock = Socket::Accept(_listen_sock,&client_ip,&client_port); 
            if(sock < 0 )
            {
                DLOG("accept sock failed\n");
                return;
            }
            //把套接字添加进epoll
            if(!Epoll::EpollCtl(_epfd,EPOLL_CTL_ADD,sock,EPOLLIN))
            {
                DLOG("add sock %d to epoll failed\n",sock);
                close(sock);
                return ;
            }
        }
        void Recver(int pos)
        {
            int sock = _events[pos].data.fd; 
            char buff[10240] = {0};
            int n = recv(sock,buff,sizeof(buff) - 1 , 0);
            if(n > 0 )
            {
                //读取成功
                buff[n] = 0;
                _handler_request(buff);

            }else if(n == 0)
            {
                //客户端断开连接
                DLOG("client #%d quit... me too \n",sock);
                bool res = Epoll::EpollCtl(_epfd,EPOLL_CTL_DEL,sock,0);
                assert(res);
                close(sock);
            }else
            {
                //出错
                DLOG("client recv %d error, close error sock\n", sock);
                bool res = Epoll::EpollCtl(_epfd,EPOLL_CTL_DEL,sock,0);
                assert(res);
                close(sock);
            }
        }

    private:
        int _listen_sock;
        uint16_t _port;
        int _epfd; 
        struct epoll_event* _events ; 
        int _events_num;
        func_t _handler_request;
    };
}
